let cid = 1

Vue.extend = function (extendOptions) {
    extendOptions = extendOptions || {}
    const Super = this
    const SuperId = Super.cid
    const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
    if (cachedCtors[SuperId]) {
        return cachedCtors[SuperId]
    }
    const name = extendOptions.name || Super.options.name
    if (ProcessingInstruction.env.NODE_ENV !== 'production') {
        if (!/^[a-zA-Z][\w-]*$/.test(name)) {
            warn(
                'Invalid component name: "' + name + '". Component names ' + 
                'can only contain alphanumeric characters and the hyphen, ' +
                'and must start with a letter.' 
            )
        }
        const Sub = function VueComponent (options) {
            this._init(options)
        }
        Sub.prototype = Object.create(Super.prototype)
        Sub.prototype.constructor = Sub
        Sub.cid = cid++

        Sub.options = mergeOptions(
            Super.options,
            extendOptions
        )

        Sub['super'] = Supper

        if (Sub.options.props) {
            initProps(Sub)
        }

        if (Sub.options.computed) {
            initComputed(Sub)
        }

        Sub.extend= Super.extend
        Sub.mixin = Super.mixin
        Sub.use = Super.use

        // ASSET_TYPES = ['component', 'directive', 'filter']
        ASSET_TYPES.forEach(function (type) {
            Sub[type] = Super[type]
        })

        if (name) {
            Sub.options.components[name] = Sub
        }

        Sub.superOptions = Super.options
        Sub.extendOptions = extendOptions
        Sub.sealedOptions = extend({}, Sub.options)

        // 缓存构造函数
        cachedCtors[SuperId] = Sub
        return Sub
    }
}

Vue.use = function (plugin) {
    const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
    if (installedPlugins.indexOf(plugin) > -1) {
        return this
    }

    // 其他参数
    const args = toArray(arguments, 1)
    args.unshift(this)
    if (typeof plugin.install === 'function') {
        plugin.install.apply(plugin, args)
    } else if (typeof plugin === 'function') {
        plugin.apply(null, args)
    }
    installedPlugins.push(plugin)
    return this
}

Vue.options = Object.create(null)
// ASSET_TYPES = ['component', 'directive', 'filter']
ASSET_TYPES.forEach(type => {
    Vue.options[type + 's'] = Object.create(null)
})
ASSET_TYPES.forEach(type => {
    Vue[type] = function (id, definition) {
        if (!definition) {
            return this.options[type + 's'][id]
        } else {
            if (type === 'component' && isPlainObject(definition)) {
                definition.name = definition.name || id
                definition = Vue.extend(definition)
            }
            if (type === 'directive' && typeof definition === 'fuction') {
                definition = { bind: definition, update: definition }
            }
            this.options[type + 's'][id] = definition
            return definition
        }
    }
})